package cs304.p3.library.framework;

import java.sql.Connection;
import java.util.List;

import javax.swing.JOptionPane;

import com.google.common.collect.Lists;

import cs304.p3.library.controller.*;
import cs304.p3.library.dao.*;
import cs304.p3.library.service.*;

// manages the single instances used throughout the application. eg. daos, services
// eager initialization of all single instances cause i'm lazy.
public class IoC {	
	
	private final static IoC ioc = new IoC();
	private final BookDao bookDao = new BookDao();
	private final BorrowerDao borrowerDao = new BorrowerDao();
	private final FineDao fineDao = new FineDao();
	private final HoldRequestDao holdRequestDao = new HoldRequestDao();
	private final DevDao devDao = new DevDao();
	
	private final BorrowerService borrowerService = new BorrowerService();
	private final ClerkService clerkService = new ClerkService();
	private final LibrarianService librarianService = new LibrarianService();
	
	private final LoginController loginController = new LoginController();
	private final MainController mainController = new MainController();
	private final DBObjectController dboController = new DBObjectController();
	private final ClerkController clerkController = new ClerkController();
	private final CheckOutBookController cobController = new CheckOutBookController(clerkController);
	private final BorrowerController borrowerController = new BorrowerController();
	private final LibrarianController librarianController = new LibrarianController();

	private Connection connection = LibraryDataAccessContext.initConnection();
	
	private IoC() {
		Dao[] daos = {bookDao, borrowerDao, fineDao, holdRequestDao, devDao};		
		for(Dao dao: daos)
			dao.setConnection(connection);
		
		Service[] services = {borrowerService, clerkService, librarianService};
		for(Service service : services) {
			service.setConnection(connection);
			service.setBookDao(bookDao);
			service.setBorrowerDao(borrowerDao);
			service.setFineDao(fineDao);
			service.setHoldRequestDao(holdRequestDao);
		}
		
		Controller[] controllers = {loginController, mainController, dboController, clerkController, borrowerController, librarianController, cobController};
		for(Controller controller : controllers) {
			controller.setBorrowerService(borrowerService);
			controller.setClerkService(clerkService);
			controller.setLibrarianService(librarianService);
		}
	}
	
	public static final void displayUserInvalidInputMessage(String msg){
		JOptionPane.showMessageDialog(null, msg, "Invalid Input", JOptionPane.ERROR_MESSAGE);
	}
	
	public static final void displayCompleteMessage(String msg){
		JOptionPane.showMessageDialog(null, msg, "Operation Complete", JOptionPane.INFORMATION_MESSAGE);
	}
	
	public static <T> T resolve(Class<T> aclass) {
		for(Object o : ioc.getObjects()) {
			if(o.getClass().equals(aclass)) {
				@SuppressWarnings("unchecked")
				T instance = (T)o;
				if(CleanUp.class.isAssignableFrom(aclass)) {
					((CleanUp)instance).cleanUp();
				}
				System.out.println("RESOLVED - " + o.getClass().getSimpleName());
				return instance;
			}
		}
		
		return null;
	}
	
	public static Connection getConnection(){
		return ioc.connection;
	}
	
	private List<Object> getObjects() {
		List<Object> objects = Lists.newArrayList();
		
		objects.add(bookDao);
		objects.add(borrowerDao);
		objects.add(fineDao);
		objects.add(holdRequestDao);
		objects.add(borrowerService);
		objects.add(clerkService);
		objects.add(librarianService);
		objects.add(loginController);
		objects.add(mainController);
		objects.add(dboController);
		objects.add(clerkController);
		objects.add(borrowerController);
		objects.add(librarianController);
		objects.add(cobController);
		objects.add(devDao);
		objects.add(connection);
		
		return objects;
	}

	public static void switchConnection(Connection connection) {
		if(connection != null) {
			ioc.connection = connection;
			Dao[] daos = {ioc.devDao, ioc.bookDao, ioc.borrowerDao, ioc.fineDao, ioc.holdRequestDao};		
			for(Dao dao: daos) dao.setConnection(connection);
		}else System.err.println("Attemp to switch to NULL CONNECTION");
	}
}
